#include "main.h"
#include "gnuplot.h"

/* Variables sur les protocoles */
int nbTotalPaquets=0;
int totalProtocoles[][30] = {{0,0,0,0,0,0},{0,0,0,0},{0,0},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; 
char *lstProtocoles[][30] = {
    {"ETH","PUP","EAP","ARP","Loopback","RARP","LLC",NULL},
    {"IPv4","IPv6","IPX","ICMP",NULL},
    {"TCP","UDP",NULL},
    {"DNS","NTP","SNMP","DHCP","DROPBOX","FTP","SSH","Telnet","SMTP","HTTP",
        "POP3","SFTP","IMAP","BGP","IRC","LDAP","HTTPS","MSN","JABBER","SIP","IRC_SERV","NETBIOS",NULL}
};

/* Composants */
CDKSCREEN *cdkscreen;           // Ecran curses
WINDOW *cursesWin;              // Window
CDKLABEL *lblTitre;             // Label de titre
CDKLABEL *lblStaticDuree;       // Label de durée de capture
CDKBUTTON *btnCapture;          // Bouton de capture
CDKLABEL *lblDuree;             // Label de durée de capture
CDKITEMLIST *choixInterface;    // Choix de l'interface
CDKSWINDOW *swindowCapture;     // Zone de capture
CDKSWINDOW *swindowInfos;       // Zone d'informations
CDKLABEL *lblTotal;
CDKSELECTION *selectPaquets;    // Selection des paquets
CDKBUTTON *btnGnuplot;          // Bouton Gnuplot

CDKENTRY *entryNameFile;        // Nom du fichier de capture


bool CaptureInProgress=false;   // Capture en cours (ou pas)
int TimeCompteur=0;             // Temps affiché au compteur
FILE *fichierCapture;           // Fichier de capture
char NomDossier[100];           // Nom du dossier de la capture courante
char NomCapture[100];           // Nom de la capture courante


pcap_t* pdes = NULL;            //Descripteur de pcap pour arreter proprement la boucle


// Affichage d'un log
void printD(char* log)
{
    char temp[200];
    sscanf(log,"%s",temp);
    int i,j;    
    for (i=0;i<4;i++)
    {
        j=0;
        while (lstProtocoles[i][j]!=NULL)
        {
            if (strcmp(temp,lstProtocoles[i][j])==0)
            {
                totalProtocoles[i][j]++;
            }
            j++;
        }
    }
    sprintf(temp,"%d : %s",TimeCompteur,log);
    addCDKSwindow(swindowCapture, copyChar(temp), BOTTOM);
    fprintf(fichierCapture,"%s",temp);
}
// Affichage d'une informations
void printM(char* log)
{
    char temp[200];
    sprintf(temp,"%d : %s",TimeCompteur,log);
    addCDKSwindow(swindowInfos, copyChar(temp), BOTTOM);
}
// Action sur le bouton de capture
int actionBtnCapture(EObjectType cdktype, void *object, void *clientData, chtype key)
{
    (void)cdktype;
    (void)object;
    (void)clientData;
    (void)key;
    if (CaptureInProgress==false) // Lancement de la capture
    {
        /* Ecran de saisie du nom du fichier */
        entryNameFile = newCDKEntry(cdkscreen,CENTER,CENTER,
                "<C>Saissisez un nom pour la capture",
                "</U/5>Nom de capture :<!U!5>",A_NORMAL,'.',vMIXED,
                40,1,100,true,false);
        char *info;
        info = activateCDKEntry(entryNameFile, 0);
        if (entryNameFile->exitType == vESCAPE_HIT)
        {
            // si je fais ECHAP dans la boite de dialogue
        }
        else if (entryNameFile->exitType == vNORMAL)
        {
            // lecture de la saisie utilisateur
            sprintf(NomCapture, "%.*s", (int)(sizeof(NomCapture) - 10), info);
            // nom de la capture
            char tempName[100];
            strcpy(tempName,"<C>Nom de la capture : ");
            strcat(tempName,NomCapture);
            printM(tempName);

            /* Gestion des droits sur les fichiers/dossiers
               (oublions pas que nous sommes en mode admin avec sudo) */
            umask(0);       // pour les droits 777

            // Création du dossier
            time_t timestamp;
            struct tm * t;
            timestamp = time(NULL);
            t = localtime(&timestamp);
            sprintf(NomDossier,"%s-%02u.%02u.%04u-%02u.%02u.%02u",NomCapture,t->tm_mday,1+t->tm_mon,1900+t->tm_year,t->tm_hour,t->tm_min,t->tm_sec);
            //sprintf(NomDossier,"%s",NomCapture);//TODO:corriger
            int res=mkdir(NomDossier,S_IRWXU | S_IRWXG | S_IRWXO);
            if (res<0)
            {
                char temp[100];
                sprintf(temp,"ECHEC a la création du dossier : %s",NomDossier);
                printM(temp);
            }
            else
            {
                char temp[100];
                sprintf(temp,"Dossier crée : %s",NomDossier);
                printM(temp);
            }

            // Fichier de capture
            char NomFichierCapture[100];
            sprintf(NomFichierCapture,"%s/%s.txt",NomDossier,NomCapture);
            if ((fichierCapture = fopen(NomFichierCapture, "w")) == NULL)
            {
                printM("Le fichier ne peut pas etre écrit");
            }
            
            /* Libération du composant */
            destroyCDKEntry(entryNameFile);

            /* Durée de capture */
            char *lblDureeTxt[1];
            lblDureeTxt[0]="   0";
            setCDKLabelMessage(lblDuree,lblDureeTxt,1);
            TimeCompteur=0;

            addCDKSwindow(swindowCapture, "</U/5>DEBUT DE LA CAPTURE", BOTTOM);
           // setCDKButtonMessage(btnCapture,"Arrêter la capture");

            CaptureInProgress=true;         // Capture en cours
            alarm(1);                       //alarme pour le timer

            /* Lancement de la capture */
            char dev[30], errbuf[PCAP_ERRBUF_SIZE];
            memset(dev,0,30*sizeof(char));
            memset(errbuf,0,PCAP_ERRBUF_SIZE*sizeof(char));
            int taille;
            int idx=0;
            chtype** liste;
            liste = getCDKItemlistValues(choixInterface,&taille);
            int selection = getCDKItemlistCurrentItem(choixInterface);
            while (liste[selection][idx]!=0){
                dev[idx]=liste[selection][idx];
                idx++;
            }
            pdes = pcap_open_live(dev,1514,IFF_PROMISC,1000,errbuf);
            if (pdes == NULL) //Erreur
            {
                printf("\npcap_open_live error : %s\n",errbuf);
                return(-1);
            }
            if (errbuf[0]!='\0') //Succes mais un warning
            {
                printf("Warning pcap_open_live : %s\n",errbuf);
            }

            Stats addr;
            addr.eth = NULL;
            addr.ip = NULL;
            int idx2;
            for(idx2=0;idx2<APP_MAX;idx2++)
            {
                addr.app[idx2]=0;
            }
            int resloop = pcap_loop(pdes,-1,print,(u_char *)&addr);  // Boucle de sniffage
            printM("Fin de la boucle\n");
            if (resloop == -2 )
            {
                pcap_close(pdes);
                pdes = NULL;
            }
            //Calcule le nombre d'adresses Ethernet
            struct ethernet_addr* eth = addr.eth;
            int nbAddrEth = 0;
            while (eth !=NULL)
            {
                nbAddrEth++;
                eth = eth->next;
            }
            char tmp[100];
            sprintf(tmp,"Nombres d'adresses ethernet différentes dans la capture : %d\n",nbAddrEth);
            printM(tmp);

        }
    }
    else
    {
        addCDKSwindow(swindowCapture, "<L>Fin de la capture.", BOTTOM);
        char plop[20];
        sprintf(plop,"<L></11>Lignes : %d",LINES);
        addCDKSwindow(swindowInfos, plop, BOTTOM);
        setCDKButtonMessage(btnCapture,"Lancer la capture");
        CaptureInProgress=false;
    }
    return 0;
}
int opengnuplot(EObjectType cdktype, void *object, void *clientData, chtype key)
{
    (void)cdktype;
    (void)object;
    (void)clientData;
    (void)key;
    gnuplot(NomCapture,NomDossier,lstProtocoles);
    return 0;
}
void stop(int sig)
{
    if (sig==SIGQUIT)
    {
        // Fermeture du fichier
        if (fichierCapture != NULL) 
        {
            fclose(fichierCapture);
            fichierCapture = NULL;
        }
        // Fin de la boucle
        if (pdes!=NULL)
        {
            pcap_breakloop(pdes);
        }
        addCDKSwindow(swindowCapture, "</U/5>FIN DE LA CAPTURE", BOTTOM);

        CaptureInProgress=false;
    }
    else if (sig==SIGALRM)
    {
        char *lblDureeTxt[1];
        lblDureeTxt[0]=malloc(sizeof(char)*6);
        char espaces[4];
        if (TimeCompteur<10) strcpy(espaces,"   ");
        else if (TimeCompteur<100) strcpy(espaces,"  ");
        else if (TimeCompteur<1000) strcpy(espaces," ");
        else strcpy(espaces,"");
        sprintf(lblDureeTxt[0],"%s%d",espaces,TimeCompteur);

        setCDKLabelMessage(lblDuree,lblDureeTxt,1);
        TimeCompteur++;
        //free(lblDureeTxt[0]);
        int i,j;
        int nbProtocoles=0;
        for (i=0;i<4;i++)
        {
            j=0;
            while (lstProtocoles[i][j]!=NULL)
            {
                nbProtocoles++;
                j++;
            }
        }
        int nbItemsPaquets=nbProtocoles+4;
        char *itemsPaquets[nbItemsPaquets];
        int k=0;
        char *temp;
        int ipv4=0,ipv6=0;
        for (i=0;i<4;i++)
        {
            temp=malloc(sizeof(char)*40);
            if (i+2 == 5)
            {
                sprintf(temp,"</11>Niveau Application");
            } else 
            {
                sprintf(temp,"</11>Niveau %d",i+2);
            }
            itemsPaquets[k++]=temp;
            j=0;
            while (lstProtocoles[i][j]!=NULL)
            {
                if (totalProtocoles[i][j]!=0) {
                    if (strcmp(lstProtocoles[i][j],"IPv4")==0)
                    {
                        ipv4 = totalProtocoles[i][j];
                    }
                    if (strcmp(lstProtocoles[i][j],"IPv6")==0)
                    {
                        ipv6 = totalProtocoles[i][j];
                    }
                    temp=malloc(sizeof(char)*100);
                    sprintf(temp,"   %s : %d",lstProtocoles[i][j],totalProtocoles[i][j]);
                    itemsPaquets[k++]=temp;
                } else {
                    nbItemsPaquets--;
                }
                j++;
            }
        }

        eraseCDKSelection(selectPaquets);
        setCDKSelectionItems(selectPaquets,itemsPaquets,nbItemsPaquets);
        sprintf(temp,"Total paquets : %d",nbTotalPaquets);
        char *lblTotalTxt[1];
        lblTotalTxt[0] = malloc(sizeof(char)*(strlen(temp)+1));
        strcpy(lblTotalTxt[0],temp);
        setCDKLabel(lblTotal,lblTotalTxt,1,false);
        refreshCDKScreen(cdkscreen);/* On affiche */
        
        if (CaptureInProgress==true)
        {
            alarm(1);
        } else {
            if (ipv4 + ipv6 != 0)
            {        
                sprintf(temp,"%d%% IPv4 et %d%% IPv6\n",(ipv4*100)/(ipv4+ipv6), (ipv6*100)/(ipv4+ipv6));
                printM(temp);
            }
            //Raz des compteurs
            nbTotalPaquets = 0;
            for (i=0;i<4;i++)
            {
                j=0;
                while (lstProtocoles[i][j]!=NULL)
                {
                   totalProtocoles[i][j]=0;
                   j++;
                }
            }
        }
    }

}
void endOfProgram()
{
    /* on nettoie avant de quitter */
    destroyCDKLabel(lblTitre);
    destroyCDKLabel(lblStaticDuree);
    destroyCDKButton(btnCapture);
    destroyCDKLabel(lblDuree);
    destroyCDKItemlist(choixInterface);
    destroyCDKSwindow(swindowCapture);
    destroyCDKSwindow(swindowInfos);
    destroyCDKButton(btnGnuplot);
    destroyCDKSelection(selectPaquets);
    destroyCDKScreen(cdkscreen);
    delwin(cursesWin);
    endCDK();
}
int main()
{
    printf("\n");
    printf("\t/-------------\\\n");
    printf("\t| Sniff-Sniff |\n");
    printf("\t\\-------------/\n");
    printf("\n");
    printf("Sniff-Sniff 1.0 (c) All rights reserved.\n");
    printf("\n");
    printf("Auteurs :\n");
    printf("\tMarie-Hélène GODDET\n");
    printf("\tDamien FINCK\n");
    printf("\n");

    int minCols=73,minLines=23,conseilCols=157,conseilLines=41;
    /* Vérifications des privilèges administrateur */
    if (geteuid()!=0)
    {
        printf("*** Veuillez executer ce programme en administrateur ! ***\n");
        exit(-1);
    }

    /* Initialisation CDK */
    cursesWin = initscr();
    cdkscreen = initCDKScreen(cursesWin);
    /* Initialisation des couleurs CDK */
    initCDKColor();


    /* Intialisation des signaux */
    signal(SIGALRM, stop);
    signal(SIGQUIT, stop);


    if (COLS<minCols || LINES<minLines)
    {
        endCDK();
        printf("Sniff-Sniff est une application semi-graphique réalisé avec curses et CDK\n");
        printf("Malheureusement, votre console est trop petite pour afficher la qualité du travail des auteurs de cette application.\n");
        printf("Votre console ne fais que %dx%d\n",COLS,LINES);
        printf("La taille minimale requise est de %dx%d\n",minCols,minLines);
        printf("La taille conseillée est de %dx%d\n",conseilCols,conseilLines);
        printf("Merci d'agrandir votre console et de relancer le programme ;)\n");
        exit(-1);
    }

    /* Positions des composants */
    int a,b,c,d,pos;
    a=COLS-69;//85
    b=4;//5
    c=a/b;
    d=a-b*c;

    /* Bouton de capture */
    if (d>0) pos=c+1;else pos=c;
    btnCapture=newCDKButton(cdkscreen,pos,0,"Lancer la capture  ",(void *)actionBtnCapture,true,false);

    /* Label de durée de capture */
    //if (d>1) pos+=21+c+1;else pos+=21+c;
    char *lblStaticDureeTxt[1];
    lblStaticDureeTxt[0]="Durée :      sec";
    lblStaticDuree = newCDKLabel(cdkscreen,pos+2,3,lblStaticDureeTxt,1,false,false);
    char *lblDureeTxt[1];
    lblDureeTxt[0]="    ";
    lblDuree = newCDKLabel(cdkscreen,pos+2+8,3,lblDureeTxt,1,false,false);

    /* Label de titre */
    if (d>1) pos+=21+c+1;else pos+=21+c;
    char *lblTitreTxt[1];
    lblTitreTxt[0]="  Sniff-Sniff  ";
    lblTitre = newCDKLabel(cdkscreen,pos,0,lblTitreTxt,1,true,true);

    /* Choix de l'interface */
    if (d>2) pos+=18+c+1;else pos+=18+c;
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_if_t* alldev;
    pcap_if_t* parcoursdev;
    pcap_addr_t* addr;
    memset(errbuf,0,PCAP_ERRBUF_SIZE*sizeof(char));
    char **interfaces;
    int nbInterface=0;
    int idx=0;
    int idx_selection=0;
    if (pcap_findalldevs(&alldev,errbuf)!=0) //Cherche toutes les interfaces
    {
        //Erreur	
        nbInterface = 1;
        interfaces = (char **)malloc(nbInterface*sizeof(char*));
        interfaces[idx]="Err";
    } else {

        parcoursdev = alldev;//On garde le début de la liste pour faire des free
        while (parcoursdev != NULL) //On compte les interfaces
        {
            nbInterface++;
            parcoursdev = parcoursdev->next;
        }
        if (nbInterface>0) {
            parcoursdev = alldev;
            interfaces = (char **)malloc(nbInterface*sizeof(char*));

            while (parcoursdev != NULL) //Parcoure les interfaces
            {
                interfaces[idx] = malloc(sizeof(char)*(strlen(parcoursdev->name)+1));
                strcpy(interfaces[idx],parcoursdev->name);
                //On regarde si l'interface a une adresse IP attribué non loopbak
                addr = parcoursdev->addresses;
                while (addr !=NULL) {
                    if (addr->netmask !=NULL && addr->broadaddr!=NULL) {
                        //Interface possedant un netmask et une adresse de broadcast
                        idx_selection = idx;
                        break;
                    }
                    addr = addr ->next;
                }
                idx++;
                parcoursdev = parcoursdev->next;
            }
        } else {
            nbInterface = 1;
            interfaces = (char **)malloc(nbInterface*sizeof(char*));
            interfaces[idx]="Err";
        }
        pcap_freealldevs(alldev);
    }

    choixInterface	= newCDKItemlist(cdkscreen,pos,0,
            "<C> Choissisez une interface : ",
            "</U/5>Interface:",interfaces,nbInterface,idx_selection,true,false);



    a=LINES-8;
    b=a/3;
    c=a-b;
    /* Zone de capture */
    swindowCapture = newCDKSwindow(cdkscreen,0,4,c,COLS-34,"<C></5>Capture",100,true,false);//100 lignes sauvegardé




    /* Nombre de paquets total */
    char *lblTotalTxt[1];
    lblTotalTxt[0]="Total paquets : 0   ";
    lblTotal = newCDKLabel(cdkscreen,COLS-30,4,lblTotalTxt,1,false,false);




    /* Selection des protocoles */
    int nbChoicesPaquets  = 1;
    //char *choicesPaquets[]= {"    ","->  "};
    char *choicesPaquets[]= {" "};


    int i,j;
    int nbProtocoles=0;
    for (i=0;i<4;i++)
    {
        j=0;
        while (lstProtocoles[i][j]!=NULL)
        {
            nbProtocoles++;
            j++;
        }
    }
    int nbItemsPaquets=nbProtocoles+4;
    char *itemsPaquets[nbItemsPaquets];
    int k=0;
    char *temp;
    for (i=0;i<4;i++)
    {
        temp=malloc(sizeof(char)*20);
        if (i+2 == 5)
        {
            sprintf(temp,"</11>Niveau App");
        } else 
        {
            sprintf(temp,"</11>Niveau %d",i+2);
        }
        itemsPaquets[k++]=temp;
        j=0;
        while (lstProtocoles[i][j]!=NULL)
        {
            temp=malloc(sizeof(char)*20);
            sprintf(temp,"   %s",lstProtocoles[i][j]);
            itemsPaquets[k++]=temp;
            j++;
        }
    }
    char *titleDKJFDF="<C></5>Protocoles :";
    selectPaquets = newCDKSelection(cdkscreen,COLS-33,5,RIGHT,c-1,31,
            titleDKJFDF,                        
            itemsPaquets,nbItemsPaquets,choicesPaquets,nbChoicesPaquets,
            A_REVERSE,true,false);

    /*for (i=0;i<nbProtocoles+3;i++)
      {
      setCDKSelectionChoice(selectPaquets,i,1);
      }*/


    /* Zone d'informations */
    swindowInfos = newCDKSwindow(cdkscreen,0,4+c+12+1,b,COLS,"<C></5>Informations",100,true,false);

    /* Bouton de gnuplot */
    btnGnuplot=newCDKButton(cdkscreen,125,4+c,"Ouvrir le graphique Gnuplot",(void *)opengnuplot,false,false);


    refreshCDKScreen(cdkscreen);/* On affiche */
    activateCDKItemlist(choixInterface,0);// on active la item list
    traverseCDKScreen(cdkscreen);/* Traverse the screen */

    /* Activation des composants */
    //activateCDKButton(btnCapture,0);
    //activateCDKSwindow(swindowCapture,0);

    endOfProgram(); // fin du pogramme

    return 0;
}
